package se.sll.service.catalogue.common;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.After;
import org.junit.Before;

/**
 * Base class for JPA test cases.
 * Helps stubbing the JPA backend database.
 * 
 * @author Christer Palm, Nogui
 */
public class JpaTestCase {
    private static final String DB_DRIVER = "org.hsqldb.jdbcDriver";
    private static final String DB_URL = "jdbc:hsqldb:mem:memdb;hsqldb.sqllog=2;hsqldb.reconfig_logging=false";
    private static final String DB_USER = "SA";
    private static final String DB_PASS = "";
    private static final Map<String, Object> properties = new HashMap<String, Object>() {
        private static final long serialVersionUID = 1L;
        {
            put("javax.persistence.jdbc.driver", DB_DRIVER);
            put("javax.persistence.jdbc.url", DB_URL);
            put("javax.persistence.jdbc.user", DB_USER);
            put("javax.persistence.jdbc.password", DB_PASS);
            put("hibernate.hbm2ddl.auto", "create");
            put("hibernate.show_sql", "false");
//            put("hibernate.formatsql", "true");
            put("hibernate.transaction.factory_class", "org.hibernate.transaction.JDBCTransactionFactory");
        }
    };
    private final String persistenceUnit;
    private final String initScript;

    private Connection connection;
    private Statement statement;
    private EntityManagerFactory entityManagerFactory;
    protected EntityManager entityManager;

    protected JpaTestCase(String persistenceUnit, String initScript) {
        this.persistenceUnit = persistenceUnit;
        this.initScript = initScript;
    }

    protected JpaTestCase(String persistenceUnit) {
        this(persistenceUnit, null);
    }

    @Before
    public void initEntityManager() throws SQLException, IOException {
        connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
        statement = connection.createStatement();
        if (DB_URL.startsWith("jdbc:hsqldb:mem:") && initScript != null) {
            runSqlScript(initScript);
        }

        entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit, properties);
        entityManager = entityManagerFactory.createEntityManager();
    }

    @After
    public void teardownEntityManager() throws SQLException {
        entityManager.close();
        entityManagerFactory.close();
        statement.close();
        connection.close();
    }

    protected void runSqlScript(String sqlScriptFilename) throws IOException, SQLException {
        SqlScript script = new SqlScript(sqlScriptFilename);
        while (script.hasNextStatement()) {
            String sqlStatement = script.nextStatement();
            runSqlStatement(sqlStatement);
        }
    }

    protected void runSqlStatement(String sqlStatement) throws SQLException {
        System.out.println("Executing statement:");
        System.out.println(sqlStatement);
        System.out.println();
        statement.execute(sqlStatement);
    }

    protected void beginTransaction() {
        entityManager.getTransaction().begin();
    }

    protected void commitTransaction() {
        entityManager.getTransaction().commit();
    }
}
